package com.tma.proximityalert;

import java.util.List;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

public class ProximityAlertActivity extends MapActivity implements
		LocationListener {

	private LocationManager mLocationManager;
	private MapView mMapView;
	private MyTargetOverlay mItemizedoverlay;
	private MyLocationOverlay mMyLocationOverlay;

	private Location mAlertPoint;

	private static final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 1; // in meters
	private static final long MINIMUM_TIME_BETWEEN_UPDATE = 1000; // in milliseconds
	private static final long POINT_RADIUS = 15; // in meters
	private static final long PROX_ALERT_EXPIRATION = -1;

	private static final String POINT_LATITUDE_KEY = "POINT_LATITUDE_KEY";
	private static final String POINT_LONGITUDE_KEY = "POINT_LONGITUDE_KEY";
	private static final String PROX_ALERT_INTENT = "com.tma.proximityalert.ProximityALert";

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_proximity_alert);

		mMapView = (MapView) findViewById(R.id.mapview);
		mMapView.setBuiltInZoomControls(true);
		mMapView.getController().setZoom(20);

		Drawable drawable = getResources().getDrawable(R.drawable.museum_naval);
		mItemizedoverlay = new MyTargetOverlay(drawable, this);

		mAlertPoint = retrieveLocationFromPreferences();
		int lat = (int) (mAlertPoint.getLatitude() * 1E6);
		int lng = (int) (mAlertPoint.getLongitude() * 1E6);
		GeoPoint point = new GeoPoint(lat, lng);
		OverlayItem overlayitem = new OverlayItem(point, "Attention", "I'm an alert point at (" + lat + ", " + lng + ")");
		mItemizedoverlay.addOverlay(overlayitem);

		mMyLocationOverlay = new MyLocationOverlay(this, mMapView);
		mMyLocationOverlay.runOnFirstFix(new Runnable() {
			public void run() {
				mMapView.getController().animateTo(
						mMyLocationOverlay.getMyLocation());
			}
		});

		List<Overlay> mapOverlays = mMapView.getOverlays();
		mapOverlays.add(mItemizedoverlay);
		mapOverlays.add(mMyLocationOverlay);

		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		boolean enabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

		if (!enabled) {
			Builder builder = new AlertDialog.Builder(this);
			builder.setMessage("The GPS is not enable. Would you like to navigate to setting to enable it?");
			builder.setCancelable(true);
			builder.setPositiveButton("OK", new OkOnClickListener());
			builder.setNegativeButton("Quit", new CancelOnClickListener());
			AlertDialog dialog = builder.create();
			dialog.show();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_proximity_alert, menu);
		return true;
	}

	@Override
	protected void onPause() {
		super.onPause();

		mLocationManager.removeUpdates(this);
		mMyLocationOverlay.disableCompass();
		mMyLocationOverlay.disableMyLocation();
	}

	@Override
	protected void onResume() {
		super.onResume();

		mMyLocationOverlay.enableCompass();
		mMyLocationOverlay.enableMyLocation();
		mLocationManager.requestLocationUpdates(
				LocationManager.GPS_PROVIDER, 
				MINIMUM_TIME_BETWEEN_UPDATE, 
				MINIMUM_DISTANCECHANGE_FOR_UPDATE, this);
	}

	@Override
	protected boolean isRouteDisplayed() {
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {

		case R.id.menu_show_me:
			mMapView.getController().animateTo(mMyLocationOverlay.getMyLocation());
			break;
		case R.id.menu_show_alert_point:
			int lat = (int) (mAlertPoint.getLatitude() * 1E6);
			int lng = (int) (mAlertPoint.getLongitude() * 1E6);
			mMapView.getController().animateTo(new GeoPoint(lat, lng));
			break;
		case R.id.menu_save_alert_point:
			saveAlertPoint();
			break;

		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onLocationChanged(Location location) {
		Location alertPoint = retrieveLocationFromPreferences();
		float distance = location.distanceTo(alertPoint);
		Toast.makeText(ProximityAlertActivity.this, "Distance from alert point: " + distance, Toast.LENGTH_LONG).show();
	}

	@Override
	public void onProviderDisabled(String provider) {
		Toast.makeText(this, "Disabled provider " + provider, Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onProviderEnabled(String provider) {
		Toast.makeText(this, "Enabled provider " + provider, Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {

	}

	private void saveAlertPoint() {
		Location location = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		if (location == null) {
			Toast.makeText(this, "No last known location. Aborting...", Toast.LENGTH_LONG).show();
			return;
		}
		
		Toast.makeText(this, "The new alert point is (" + location.getLatitude() + ", " + location.getLongitude() + ")", Toast.LENGTH_LONG).show();

		mAlertPoint = location;
		int lat = (int) (mAlertPoint.getLatitude() * 1E6);
		int lng = (int) (mAlertPoint.getLongitude() * 1E6);
		GeoPoint point = new GeoPoint(lat, lng);
		OverlayItem overlayitem = new OverlayItem(point, "Attention", "I'm an alert point at (" + lat + ", " + lng + ")");
		mItemizedoverlay.clear();
		mItemizedoverlay.addOverlay(overlayitem);

		saveLocationInPreferences((float) location.getLatitude(), (float) location.getLongitude());
		addProximityAlert(location.getLatitude(), location.getLongitude());
	}

	private void addProximityAlert(double latitude, double longitude) {

		Intent intent = new Intent(PROX_ALERT_INTENT);
		PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intent, 0);

		mLocationManager.removeProximityAlert(proximityIntent);
		mLocationManager.addProximityAlert(latitude, 
				longitude, 
				POINT_RADIUS, 
				PROX_ALERT_EXPIRATION, // time for this proximity alert, in milliseconds, or -1 to indicate no expiration
				proximityIntent // will be used to generate an Intent to fire
								// when entry to or exit from the alert region
								// is detected
				);

		IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);
		registerReceiver(new ProximityIntentReceiver(), filter);

	}

	private void saveLocationInPreferences(float latitude, float longitude) {
		SharedPreferences prefs = this.getSharedPreferences(getClass()
				.getSimpleName(), Context.MODE_PRIVATE);
		SharedPreferences.Editor prefsEditor = prefs.edit();
		prefsEditor.putFloat(POINT_LATITUDE_KEY, latitude);
		prefsEditor.putFloat(POINT_LONGITUDE_KEY, longitude);
		prefsEditor.commit();
	}

	private Location retrieveLocationFromPreferences() {
		SharedPreferences prefs = this.getSharedPreferences(getClass().getSimpleName(), Context.MODE_PRIVATE);
		Location location = new Location("prefs");
		location.setLatitude(prefs.getFloat(POINT_LATITUDE_KEY, 0));
		location.setLongitude(prefs.getFloat(POINT_LONGITUDE_KEY, 0));
		return location;
	}

	private final class CancelOnClickListener implements
			DialogInterface.OnClickListener {

		public void onClick(DialogInterface dialog, int which) {
			ProximityAlertActivity.this.finish();
		}

	}
	
	private final class OkOnClickListener implements
			DialogInterface.OnClickListener {

		public void onClick(DialogInterface dialog, int which) {
			Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
			startActivity(intent);
		}

	}

}
